#include "asteroids.h"

/***************************************************************
 * Asteroids constructor
 ***************************************************************/
Asteroids::Asteroids()
{
   for (int i = 0; i < MAX_BIG_ROCKS; i++)
      m_rocks.push_back(new BigRock());
}

/***************************************************************
 * Operator ++ : Moves the game forward
 ***************************************************************/
void Asteroids::operator ++ (int postfix)
{
   m_ship++;

   for (int i = 0; i < MAX_BULLETS; i++)
      if (m_bullets[i].isFired())
      {
         if (m_bullets[i].getCountdown() == 0)
            m_bullets[i] = Bullet();
         m_bullets[i].subtractFromCountdown();
      }

   for (int i = 0; i < MAX_BULLETS; i++)
      m_bullets[i]++;

   list <Rock *>::iterator it;
   for (it = m_rocks.begin(); it != m_rocks.end(); it++)
   {
      (*(*it))++;
      for (int iBullet = 0; iBullet < MAX_BULLETS; iBullet++)
         if (minDist(it, (*it)->getRadius(), iBullet) < (*it)->getRadius())
         {
            (*it)->setHit(true);
            it = m_rocks.erase(it);
         }
   }
}

/***************************************************************
 * draw stuff
 ***************************************************************/
void Asteroids::draw()
{
   m_ship.draw();
   m_score.drawScore();

   for (int i = 0; i < MAX_BULLETS; i++)
      m_bullets[i].draw();

   list <Rock *>::iterator it;
   for (it = m_rocks.begin(); it != m_rocks.end(); it++)
      (*it)->draw();
}

/***************************************************************
 * Interact
 * Takes the users input and determines what to do with it.
 ***************************************************************/
void Asteroids::interact(const Interface *pUI)
{
   // Tells when the 'Up', 'Left', 'Right' arrow keys are pressed
   m_ship.event(pUI->isUp(), pUI->isLeft(), pUI->isRight());

   if (pUI->isSpace() || pUI->isF1())
      fire();
}

/**********************************************************
 * fire : fires bullets
 **********************************************************/
void Asteroids::fire()
{
   // we only want to have this function used five times,
   // starting at zero uses
   static int iBullet = 0;

   for (int i = 0; i < MAX_BULLETS; i++)
   {
      m_bullets[iBullet].setWrap (true);
      m_bullets[iBullet].setFired(true);
      m_bullets[iBullet].setPoint(m_ship.getPoint());
      // give that bullet a magnitude
      m_bullets[iBullet].setDx((-sin(deg2rad(m_ship.getAngle())) * 5) + m_ship.getDx());
      m_bullets[iBullet].setDy(( cos(deg2rad(m_ship.getAngle())) * 5) + m_ship.getDy());
   }
   // if the function has been called MAX_BULLET times, reset to zero
   if (++iBullet == MAX_BULLETS)
      iBullet = 0;
}

/**********************************************************
 **********************************************************
 **********************************************************/

/***************************************************************
 * Get Max Value
 * Returnes the greatest value of the bird and the bullets.
 *
 ***************************************************************/
float Asteroids::getMaxValue(list <Rock *>::iterator &iRock, int &iBullet)
{
   float max = 0;
   // finds the highest value out of all the bullets and birds
   // values
   max = (m_bullets[iBullet].getDx() > m_bullets[iBullet].getDy()) ? m_bullets[iBullet].getDx() : m_bullets[iBullet].getDy();

   max = (max > (*iRock)->getX()) ? max : (*iRock)->getX();
   max = (max > (*iRock)->getY()) ? max : (*iRock)->getY();

   return max;
}

/***************************************************************
 * Get Min Value
 * Returnes the smallets of the given two values.
 *
 ***************************************************************/
float Asteroids::getMinValue(float distSqrd, float min)
{
   // not much to explain here..
   if (distSqrd < min)
      return distSqrd;
   else
      return min;
}

/***************************************************************
 * Min Distance
 * Finds and returns the smallest distance of the bullets and
 * bird.
 *
 ***************************************************************/
float Asteroids::minDist(list <Rock *>::iterator &iRock, int radius, int &iBullet)
{
   float max = getMaxValue(iRock, iBullet); // set the max value
   float min = radius * radius; // make the default min to return 10

   float distanceSquared;

   for (int i = 0; i < max; i++)
   {
         distanceSquared = (((m_bullets[iBullet].getX() + m_bullets[iBullet].getDx() * i / max) -
                            ((*iRock)->getX() + (*iRock)->getDx() * i / max))
                            *
                            ((m_bullets[iBullet].getX() + m_bullets[iBullet].getDx() * i / max) -
                            ((*iRock)->getX() + (*iRock)->getDx() * i / max)))
                           +
                           (((m_bullets[iBullet].getY() + m_bullets[iBullet].getDy() * i / max) -
                            ((*iRock)->getY() + (*iRock)->getDy() * i / max))
                            *
                            ((m_bullets[iBullet].getY() + m_bullets[iBullet].getDy() * i / max) -
                            ((*iRock)->getY() + (*iRock)->getDy() * i / max)));

         min = getMinValue(distanceSquared, min);
   }

   return sqrt(min); // returns the smallest distance
}
